/*************************************************************
   Copyright(C) 2021 by WuIslet
   All rights reserved.
   
   UISceneToolWindow.cs
   UnityFramework
   
   Created by WuIslet on 2021-05-18.
   
*************************************************************/
#define USE_LUA_CODE1
#define USE_CSHARP_CODE

#if !USE_ILRUNTIME
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;

// 统一命名：
// Window - 界面
// UIEditorData - 编辑模式下的界面数据
// UIEditorSceneManager(Manager) - 界面编辑器
// UISceneTool - 菜单工具集
// prefab - 预制体
// 
// TODO 
// 1. 界面中文别名/tag。配套搜索功能
// 持续优化
// 1. 绑定注册的按钮类型全覆盖
// 2. UIControlData对于类型的识别覆盖
// 3. ui规范化的规则增加
// 5. 各种组件的初始化
// 6. UIEditorData保存数据的增加

public class UISceneToolWindow : EditorWindow, IHasCustomMenu
{
    private static Encoding utf8noBom = new UTF8Encoding(false);
    private const bool isAdministrator = true;

    private static UISceneToolWindow window;
    [MenuItem("Tools/UI场景工具 &Q")]
    public static void AddWindow()
    {
        if (window == null)
        {
            window = EditorWindow.GetWindow<UISceneToolWindow>("UI场景工具", true, UnityEditorWindowHelper.GetWindowType(EditorWindowType.Inspector));
            window.minSize = new Vector2(275f, 700f);
            window.Show();
        }
    }

    private void OnEnable()
    {
        window = this;
        richStyle.richText = true;
        LocalConfigManager.Inst.SetLocalConfigBaseSetting(LocalConfigserializationType.Json, Path.Combine("Assets/ThirdParty/isletTools/UIWidgetAsset", "SceneTools.cfg"));
        ReadConfig();
#if ExtraFunc
        InitDesignPicture();
#endif
        InitDragFunction();
        InitRightMenu();
        InitPrefabFormat();
        InitHightLightUIControlData();
        InitSelectionDetective();

        InitUIAssetRawData();
        if (PrefabStageUtility.GetCurrentPrefabStage() != null)
            Refresh();
    }

    private void OnDisable()
    {
        window = null;
        WriteConfig();
#if ExtraFunc
        ClearDesignPicture();
#endif
        ClearDragFunction();
        ClearRightMenu();
        ClearPrefabFormat();
        ClearHightLightUIControlData();
        ClearSelectionDetective();
    }

#if USE_LUA_CODE
    private static string UIDefCodeBegin;
    private static string UIDefCodeEnd;
    private void ReadConfig()
    {
        ReadTemplatePrefab();
        UIDefCodeBegin = LocalConfigManager.Inst.GetRawData("UIDefCodeBegin");
        UIDefCodeEnd = LocalConfigManager.Inst.GetRawData("UIDefCodeEnd");
        if (string.IsNullOrEmpty(UIDefCodeBegin))
        {
            UIDefCodeBegin = "--Generate Code Begin";
        }
        if (string.IsNullOrEmpty(UIDefCodeEnd))
        {
            UIDefCodeEnd = "--Generate Code End";
        }
    }

    private void WriteConfig()
    {
        if (isAdministrator)
        {
            WriteTemplatePrefab();
            LocalConfigManager.Inst.SetRawData("UIDefCodeBegin", UIDefCodeBegin);
            LocalConfigManager.Inst.SetRawData("UIDefCodeEnd", UIDefCodeEnd);
        }
    }
#endif
#if USE_CSHARP_CODE
    private static string UIDefDefineBegin;
    private static string UIDefDefineEnd;
    private static string UIDefCodeBegin;
    private static string UIDefCodeEnd;
    private void ReadConfig()
    {
        ReadTemplatePrefab();
        UIDefDefineBegin = LocalConfigManager.Inst.GetRawData("UIDefDefineBegin");
        UIDefDefineEnd = LocalConfigManager.Inst.GetRawData("UIDefDefineEnd");
        UIDefCodeBegin = LocalConfigManager.Inst.GetRawData("UIDefCodeBegin");
        UIDefCodeEnd = LocalConfigManager.Inst.GetRawData("UIDefCodeEnd");
        if (string.IsNullOrEmpty(UIDefDefineBegin))
        {
            UIDefDefineBegin = "//Generate Define Begin";
        }
        if (string.IsNullOrEmpty(UIDefDefineEnd))
        {
            UIDefDefineEnd = "//Generate Define End";
        }
        if (string.IsNullOrEmpty(UIDefCodeBegin))
        {
            UIDefCodeBegin = "//Generate Code Begin";
        }
        if (string.IsNullOrEmpty(UIDefCodeEnd))
        {
            UIDefCodeEnd = "//Generate Code End";
        }
    }

    private void WriteConfig()
    {
        if (isAdministrator)
        {
            WriteTemplatePrefab();
            LocalConfigManager.Inst.SetRawData("UIDefDefineBegin", UIDefDefineBegin);
            LocalConfigManager.Inst.SetRawData("UIDefDefineEnd", UIDefDefineEnd);
            LocalConfigManager.Inst.SetRawData("UIDefCodeBegin", UIDefCodeBegin);
            LocalConfigManager.Inst.SetRawData("UIDefCodeEnd", UIDefCodeEnd);
        }
    }
#endif

    #region TAB
    string[] _tabLabels = new[] { "美术工具", "程序工具" };
    int _selectedTab;
    #endregion TAB

    private void OnGUI()
    {
        #region TAB
        if (isUseAdminTool)
        {
            _tabLabels = new[] { "美术工具", "程序工具", "其他工具", "Debug工具" };
        }
        else if (isUseDebugTool)
        {
            _tabLabels = new[] { "美术工具", "程序工具", "Debug工具" };
        }
        else
        {
            _tabLabels = new[] { "美术工具", "程序工具", };
        }
        _selectedTab = GUILayout.Toolbar(_selectedTab, _tabLabels);
        #region 分割线
        GUILayout.Space(12f);
        Rect rect = GUILayoutUtility.GetLastRect();
        GUI.color = new Color(0.0f, 0.0f, 0.0f, 0.25f);
        GUI.DrawTexture(new Rect(0.0f, rect.yMin + 6.0f, Screen.width, 4.0f), EditorGUIUtility.whiteTexture);
        GUI.DrawTexture(new Rect(0.0f, rect.yMin + 6.0f, Screen.width, 1.0f), EditorGUIUtility.whiteTexture);
        GUI.DrawTexture(new Rect(0.0f, rect.yMin + 9.0f, Screen.width, 1.0f), EditorGUIUtility.whiteTexture);
        GUI.color = Color.white;
        #endregion 分割线
        switch (_selectedTab)
        {
            case 0:
                DrawTab1Page();
                break;
            case 1:
                DrawTab2Page();
                break;
            case 2:
                if (isUseAdminTool)
                {
                    DrawTab3Page();
                }
                else
                {
                    DrawTab4Page();
                }
                break;
            case 3:
                if (isUseAdminTool)
                {
                    DrawTab4Page();
                }
                else
                {
                    DrawTab1Page();
                }
                break;
            default:
                DrawTab1Page();
                break;
        }
        #endregion TAB

        DrawRightClick();
    }

    #region 右上配置菜单
    public bool isUseDebugTool = false;
    public bool isUseAdminTool = false;
    public static bool isUseTagTool = false;

    void IHasCustomMenu.AddItemsToMenu(GenericMenu menu)
    {
        menu.AddItem(new GUIContent("Debug模式"), isUseDebugTool, DebugMenuClick);
        menu.AddItem(new GUIContent("开启全部工具"), isUseAdminTool, AdminMenuClick);
        menu.AddItem(new GUIContent("Tag检查模式"), isUseTagTool, TagMenuClick);
        menu.AddSeparator("");
        menu.AddItem(new GUIContent("打开工具代码"), false, OpenEditorWindowCode);
        menu.AddItem(new GUIContent("强制刷新"), false, ForceRefresh);
    }

    private void DebugMenuClick()
    {
        isUseDebugTool = !isUseDebugTool;
        if (!isUseDebugTool && _selectedTab >= 2)
            _selectedTab = 0;
        if (isUseAdminTool && isUseDebugTool)
        {
            isUseAdminTool = false;
            _selectedTab = 0;
        }
    }

    private void AdminMenuClick()
    {
        isUseAdminTool = !isUseAdminTool;
        if (!isUseAdminTool && _selectedTab >= 2)
            _selectedTab = 0;
        if (isUseAdminTool && isUseDebugTool)
        {
            isUseDebugTool = false;
            _selectedTab = 0;
        }
    }

    private void TagMenuClick()
    {
        isUseTagTool = !isUseTagTool;
    }

    private void ForceRefresh()
    {
        Refresh();
    }
    #endregion 右上配置菜单

    #region 美术
    private static bool isRaycastTarget = true;
    private bool isPrefabSetting = false; //TODO 改成分辨率的编辑窗口模式
    private Vector2 templateScrollPos;
    private void DrawTab1Page()
    {
#if ExtraFunc
        if (GUILayout.Button("刷新模板数据"))
        {
            ReadTemplatePrefab();
        }
        isRaycastTarget = EditorGUILayout.Toggle("RaycastTarget显示：", isRaycastTarget);

        var sel = Selection.activeGameObject;
        if (sel != null)
        {
            var ele = sel.GetComponent<ILayoutElement>();
            if (ele != null)
            {
                EditorGUILayout.LabelField("testheight: " + ele.preferredHeight);
            }
        }

        var strID = FindUIID(Selection.activeGameObject);
        if (!string.IsNullOrEmpty(strID))
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("界面id:", GUILayout.MaxWidth(60));
            EditorGUILayout.SelectableLabel(strID);
            EditorGUILayout.EndHorizontal();
        }

        EditorGUILayout.BeginVertical("Box");
        if (PrefabStageUtility.GetCurrentPrefabStage() != null)
        {
            DrawDesignPicture();
        }
        else if (Selection.gameObjects.Length == 1 && Selection.activeGameObject != null)
        {
            if (GUILayout.Button("Open Prefab"))
            {
                AssetDatabase.OpenAsset(Selection.activeInstanceID);
            }
        }
        else
        {
            //todo 绘制用名字新建或打开prefab界面
            //DrawCreateOrOpenScene();
        }

        EditorGUILayout.EndVertical();

        GUILayout.Space(30);
        EditorGUILayout.BeginVertical("Box");
        DrawChangeAspect();
        EditorGUILayout.EndVertical();

        if (UIEditorDatas.Count > 0 && PrefabStageUtility.GetCurrentPrefabStage() != null)
        {
            var uiData = UIEditorDatas[0]; //todo 没有适配多个data的情况！！！
            if (GUILayout.Button("SVN提交"))
            {
                if (uiData.IsVaild())
                {
                    var cnt = CtrlItemDataHelper.AutoFindComponents(Prefabs[0], uiData.ctrlItemDatas);
                    if (cnt > 0 || !CheckErrors(uiData, false))
                    {
                        EditorUtility.DisplayDialog("错误", "修复代码失败，提交后请通知程序进行修复", "OK");
                    }
                    else
                    {
                        GenerateCode(uiData);
                        DoSVNCommit(uiData, PrefabStageUtility.GetCurrentPrefabStage().assetPath);
                    }
                }
            }
        }

        GUILayout.Space(30);
#endif
        templateScrollPos = EditorGUILayout.BeginScrollView(templateScrollPos);
        DrawTemplatePrefab(isPrefabSetting);
        EditorGUILayout.EndScrollView();
    }
    
#if ExtraFunc
    private static string[] mAllAspect = null;
    private int mCurAspectIndex = 0;
    private bool mIsLiuHai = false;
    private void DrawChangeAspect()
    {
        if (mAllAspect == null)
        {
            mAllAspect = GameViewUtils.GetAllAsp(GameViewSizeGroupType.Standalone);
        }
        EditorGUI.BeginChangeCheck();
        var aspect = EditorGUILayout.Popup("改变分辨率：", mCurAspectIndex, mAllAspect);
        var mBoolIsLiuHai = EditorGUILayout.Toggle("模拟刘海：", mIsLiuHai);
        if (EditorGUI.EndChangeCheck())
        {
            if (mIsLiuHai != mBoolIsLiuHai)
            {
                mIsLiuHai = mBoolIsLiuHai;
                RefreshAllUIPrefabSafeArea();
            }
            if (mCurAspectIndex != aspect)
            {
                mCurAspectIndex = aspect;
                RefreshAllUIPrefabSafeArea();
                GameViewUtils.SetSizeIndex(mCurAspectIndex);
            }
        }
    }

    #region 效果图
    private GameObject mGO_UIDesignPicture;
    private RawImage mImg_UIDesignPicture;
    private void InitDesignPicture()
    {
        mGO_UIDesignPicture = AssetDatabase.LoadAssetAtPath<GameObject>(Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UIDesignPicture.prefab"));
        mImg_UIDesignPicture = mGO_UIDesignPicture.GetComponentInChildren<RawImage>(true);
    }

    private void ClearDesignPicture()
    {

    }

    private void DrawDesignPicture()
    {
        GUILayout.Label("修改效果图：");
        EditorGUI.BeginChangeCheck();
        var mBool_UIDesignPicture = EditorGUILayout.Toggle("显示：", mImg_UIDesignPicture.gameObject.activeSelf);
        var rect = mImg_UIDesignPicture.gameObject.GetRectTransform();
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.BeginVertical();
        EditorGUILayout.LabelField("Width");
        var newWidth = EditorGUILayout.DelayedFloatField(rect.sizeDelta.x);
        EditorGUILayout.EndVertical();
        EditorGUILayout.BeginVertical();
        EditorGUILayout.LabelField("Height");
        var newHeight = EditorGUILayout.DelayedFloatField(rect.sizeDelta.y);
        EditorGUILayout.EndVertical();
        EditorGUILayout.EndHorizontal();
        var newAlpha = EditorGUILayout.Slider(mImg_UIDesignPicture.color.a, 0, 1);
        var texture = EditorGUILayout.ObjectField("效果图：", mImg_UIDesignPicture.texture, typeof(Texture), true) as Texture;

        if (EditorGUI.EndChangeCheck())
        {
            if (mImg_UIDesignPicture.gameObject.activeSelf != mBool_UIDesignPicture)
            {
                mImg_UIDesignPicture.gameObject.SetActive(mBool_UIDesignPicture);
            }
            if (newWidth != mImg_UIDesignPicture.rectTransform.sizeDelta.x)
            {
                mImg_UIDesignPicture.rectTransform.sizeDelta = new Vector2(newWidth, mImg_UIDesignPicture.rectTransform.sizeDelta.y);
            }
            if (newHeight != mImg_UIDesignPicture.rectTransform.sizeDelta.y)
            {
                mImg_UIDesignPicture.rectTransform.sizeDelta = new Vector2(mImg_UIDesignPicture.rectTransform.sizeDelta.x, newHeight);
            }
            if (newAlpha != mImg_UIDesignPicture.color.a)
            {
                mImg_UIDesignPicture.color = new Color(mImg_UIDesignPicture.color.r, mImg_UIDesignPicture.color.g,
                    mImg_UIDesignPicture.color.b, newAlpha);
            }
            if (texture != mImg_UIDesignPicture.texture)
            {
                mImg_UIDesignPicture.texture = texture;
            }
            SaveDesignPicture();
        }
    }

    private void SaveDesignPicture()
    {
        EditorUtility.SetDirty(mGO_UIDesignPicture);
        AssetDatabase.SaveAssets();
    }
    #endregion 效果图
#endif
    #region 模板prefab
    private class TemplatePrefabData //模板prefab
    {
        public string path;
        public string name;
    }

    private class TemplatePrefabGroupData //模板组
    {
        public string name;
        [System.NonSerialized] public bool foldout;
        public List<TemplatePrefabData> datas;
    }

    private int DragControlID = 0;
    private string DragControlKey = "";
    private bool m_IsDragPerformed = false;
    private int DragExcuteGroup = -1;

    private List<TemplatePrefabGroupData> TemplateZone = new List<TemplatePrefabGroupData>();

    private void ReadTemplatePrefab()
    {
        var str = LocalConfigManager.Inst.GetRawData("TemplateZone", isForceRefresh: true);
        if (string.IsNullOrEmpty(str))
        {
            TemplateZone = new List<TemplatePrefabGroupData>();
        }
        else
        {
            TemplateZone = LitJson.JsonMapper.ToObject<List<TemplatePrefabGroupData>>(str);
            for (int i = TemplateZone.Count - 1; i >= 0; --i)
            {
                var list = TemplateZone[i].datas;
                for (int j = 0; j < list.Count; ++j)
                {
                    if (!File.Exists(list[j].path))
                    {
                        list.RemoveAt(j);
                    }
                }
            }
        }
    }

    private void WriteTemplatePrefab()
    {
        var str = LitJson.JsonMapper.ToJson(TemplateZone);
        LocalConfigManager.Inst.SetRawData("TemplateZone", str);
    }
    private void DrawTemplatePrefab(bool isSetting)
    {
        if (TemplateZone.Count <= 0)
        {
            if (GUILayout.Button("增加模板组"))
            {
                TemplateZone.Add(new TemplatePrefabGroupData() { name = "新建模板", foldout = false, datas = new List<TemplatePrefabData>() });
            }
            return;
        }
        for (int i = 0; i < TemplateZone.Count; ++i)
        {
            var groupData = TemplateZone[i];
            var rect = EditorGUILayout.BeginVertical("Box", GUILayout.MaxWidth(300));
            {
                EditorGUILayout.BeginHorizontal();
                if (isSetting)
                {
                    groupData.name = EditorGUILayout.TextField(groupData.name, GUILayout.MaxWidth(200));
                }
                else
                {
                    GUILayout.Label(groupData.name + "：");
                }
                GUILayout.Label(string.Format("共有{0}个模板", groupData.datas.Count));
                groupData.foldout = EditorGUILayout.Foldout(groupData.foldout, groupData.foldout ? "收起" : "展开", true);
                if (isSetting)
                {
                    if (GUILayout.Button("增", GUILayout.MaxWidth(30)))
                    {
                        TemplateZone.Insert(i + 1, new TemplatePrefabGroupData(){name = "新建模板", foldout = false, datas = new List<TemplatePrefabData>()});
                        EditorGUILayout.EndHorizontal();
                        EditorGUILayout.EndVertical();
                        return;
                    }
                    if (GUILayout.Button("删", GUILayout.MaxWidth(30)))
                    {
                        TemplateZone.RemoveAt(i);
                        EditorGUILayout.EndHorizontal();
                        EditorGUILayout.EndVertical();
                        return;
                    }
                }
                EditorGUILayout.EndHorizontal();
                if (groupData.foldout)
                {
                    if (groupData.datas.Count == 0)
                    {
                        GUILayout.Space(30);
                    }
                    else
                    {
                        for (int j = 0; j < groupData.datas.Count; ++j)
                        {
                            DrawSingleTemplatePrefab(i, groupData.datas[j], j, isSetting);
                        }
                    }
                }
            }
            EditorGUILayout.EndVertical();
            DragTemplatePrefabExcute(rect, i);
        }
    }
    private void DrawSingleTemplatePrefab(int group, TemplatePrefabData data, int i, bool isSetting)
    {
        if (isSetting)
        {
            EditorGUILayout.BeginHorizontal();
            {
                data.name = EditorGUILayout.TextField(data.name, GUILayout.MaxWidth(400));
                if (GUILayout.Button("开", GUILayout.MaxWidth(30)))
                {
                    OpenTemplatePrefab(group, i);
                }

                if (GUILayout.Button("删", GUILayout.MaxWidth(30)))
                {
                    RemoveTemplatePrefab(group, i);
                }

                if (GUILayout.Button("上", GUILayout.MaxWidth(30)))
                {
                    MoveTemplatePrefab(group, i, -1);
                }

                if (GUILayout.Button("下", GUILayout.MaxWidth(30)))
                {
                    MoveTemplatePrefab(group, i, 1);
                }
            }
            EditorGUILayout.EndHorizontal();
        }
        else
        {
            EditorGUILayout.LabelField(data.name, EditorStyles.miniButton, GUILayout.MaxWidth(400));
            var rect = GUILayoutUtility.GetLastRect();
            if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && rect.Contains(Event.current.mousePosition))
            {
                DragControlID = GUIUtility.GetControlID(15 + i, FocusType.Passive); //TODO get real control ID
                CreateTemplatePrefabWithDrag(TemplateZone[group].datas[i].path, DragControlID);
                Event.current.Use();
            }
        }
        GUILayout.Space(10);
    }

    private void DragTemplatePrefabExcute(Rect rect, int group)
    {
        if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && rect.Contains(Event.current.mousePosition))
        {
            EditorMenu?.ShowAsContext();
            Event.current.Use();
        }
        if (Event.current.type == EventType.DragUpdated && rect.Contains(Event.current.mousePosition))
        {
            if (!string.IsNullOrEmpty(DragControlKey))
            {
                if (DragAndDrop.paths.Length > 0 && DragAndDrop.paths[0] == DragControlKey)
                {
                    return;
                }
                else
                {
                    DragControlKey = "";
                }
            }
            else if(DragAndDrop.paths.Length == 1 && DragAndDrop.objectReferences.Length == 1 && DragAndDrop.objectReferences[0] is GameObject) //只有一个prefab的时候
            {
                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                DragExcuteGroup = group;
                Event.current.Use();
            }
        }
        else if (Event.current.type == EventType.DragPerform && DragExcuteGroup == group)
        {
            var obj = DragAndDrop.objectReferences[0];
            string path = DragAndDrop.paths[0];
            AddTemplatePrefab(path, group);
        }
    }
    private void AddTemplatePrefab(string path, int group)
    {
        var find = false;
        for (int i = 0; i < TemplateZone[group].datas.Count; ++i)
        {
            if (TemplateZone[group].datas[i].path == path)
            {
                find = true;
                break;
            }
        }
        if (find)
            return;

        var name = Path.GetFileNameWithoutExtension(path);
        var data = new TemplatePrefabData() {path = path, name = name};
        TemplateZone[group].datas.Add(data);
        WriteTemplatePrefab();
    }
    private void RemoveTemplatePrefab(int group, int index)
    {
        if (0 > index || index >= TemplateZone[group].datas.Count)
            return;

        TemplateZone[group].datas.RemoveAt(index);
        WriteTemplatePrefab();
    }
    private void MoveTemplatePrefab(int group, int index, int offset)
    {
        var newIndex = index + offset;
        if (0 > newIndex || newIndex >= TemplateZone[group].datas.Count)
            return;

        var prefab = TemplateZone[group].datas[index];
        TemplateZone[group].datas.RemoveAt(index);
        TemplateZone[group].datas.Insert(newIndex, prefab);
    }
    private void OpenTemplatePrefab(int group, int index)
    {
        var prefab = TemplateZone[group].datas[index];
        var go = AssetDatabase.LoadAssetAtPath<GameObject>(prefab.path);
        AssetDatabase.OpenAsset(go.GetInstanceID());
    }

    #region DragFunction
    private void CreateTemplatePrefabWithDrag(string path, int ControlID)
    {
        m_IsDragPerformed = false;
        DragControlKey = ControlID.ToString();
        var name = Path.GetFileNameWithoutExtension(path);
        var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
        DragAndDrop.PrepareStartDrag();
        DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
        DragAndDrop.paths = new[] { DragControlKey };
        DragAndDrop.objectReferences = new UnityEngine.Object[] { prefab };
        DragAndDrop.StartDrag($"Create {name}");
    }

    private void InitDragFunction()
    {
        SceneView.duringSceneGui += SceneGUIUpdate;
        EditorApplication.hierarchyWindowItemOnGUI += HierarchyGUIUpdate;
        EditorApplication.projectWindowItemOnGUI += ProjectGUIUpdate;
    }

    private void ClearDragFunction()
    {
        SceneView.duringSceneGui -= SceneGUIUpdate;
        EditorApplication.hierarchyWindowItemOnGUI -= HierarchyGUIUpdate;
        EditorApplication.projectWindowItemOnGUI -= ProjectGUIUpdate;
    }

    private void SceneGUIUpdate(SceneView sv)
    {
        OnDragEnd();
    }

    private void HierarchyGUIUpdate(int id, Rect rect)
    {
        OnDragEnd();
    }

    private void ProjectGUIUpdate(string str, Rect rect)
    {
        if (!string.IsNullOrEmpty(DragControlKey))
        {
            if (DragAndDrop.paths.Length > 0 && DragAndDrop.paths[0] == DragControlKey)
            {
                DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
            }
            else if (Event.current.type == EventType.DragPerform || Event.current.type == EventType.DragExited)
            {
                DragControlKey = "";
            }
        }
    }

    GameObject _NewSelect = null;
    private void OnDragEnd()
    {
        if (!string.IsNullOrEmpty(DragControlKey))
        {
            if (DragAndDrop.paths.Length > 0 && DragAndDrop.paths[0] == DragControlKey)
            {
                if (Event.current.type == EventType.DragPerform)
                {
                    m_IsDragPerformed = true;
                }

                if (Event.current.type == EventType.DragExited)
                {
                    if (m_IsDragPerformed)
                    {
                        m_IsDragPerformed = false;
                        DragControlKey = "";

                        var go = Selection.activeGameObject;
                        // Do your **OnDragEnd callback on go** here
                        var newGo = GameObject.Instantiate(go);
                        newGo.transform.parent = go.transform.parent;
                        newGo.transform.SetSiblingIndex(go.transform.GetSiblingIndex());
                        newGo.transform.localPosition = go.transform.localPosition;
                        newGo.transform.localRotation = go.transform.localRotation;
                        newGo.name = go.name;
                        Selection.activeGameObject = newGo;
                        GameObject.DestroyImmediate(go);
                        _NewSelect = newGo;
                    }
                }
            }
            else if (Event.current.type == EventType.DragPerform || Event.current.type == EventType.DragExited)
            {
                DragControlKey = "";
            }
        }

        if (_NewSelect != null && Selection.activeGameObject != _NewSelect)
        {
            Selection.activeGameObject = _NewSelect;
            _NewSelect = null;
        }
    }
    #endregion DragFunction
    #endregion 模板prefab

    #endregion 美术

    #region 程序
    #region 选中检测
    public static string selectionPath = "";
    public static bool isJump2Target = false;
    private void InitSelectionDetective()
    {
        selectionPath = "";
        isJump2Target = false;
        Selection.selectionChanged += selectionCallback;
    }

    private void ClearSelectionDetective()
    {
        selectionPath = "";
        isJump2Target = false;
        Selection.selectionChanged -= selectionCallback;
    }

    private void selectionCallback()
    {
        selectionPath = "";
        isJump2Target = false;
        if (Selection.gameObjects.Length > 0)
        {
            var curSel = Selection.gameObjects[0];
            var curScene = curSel.scene;
            if (curScene.IsValid() && EditorSceneManager.IsPreviewScene(curSel.scene)) // 如果是在prefab预览状态下。
            {
                isJump2Target = true;
                selectionPath = curSel.transform.GetUIRelativePath();
            }
            if (Application.isPlaying && playingWatchPrefab != null)
            {
                var rootName = curSel.transform.GetUIRootGameObject();
                if (rootName == playingWatchPrefab.name)
                {
                    isJump2Target = true;
                    selectionPath = curSel.transform.GetUIRelativePath();
                }
            }
        }
        Repaint();
    }
    #endregion 选中检测
    public List<GameObject> Prefabs = new List<GameObject>(4);
    public List<UIEditorData> UIEditorDatas = new List<UIEditorData>(4);
    public List<bool> _foldouts = new List<bool>();
    public bool withClickFunc = true;
    private bool _foldWarning;
    private UIEditorData copyData;

    private void DrawTab2Page()
    {
        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        if (!Application.isPlaying && prefabStage != null && prefabStage.scene.isDirty) //TODO 目前工具都用objectid为索引的依据，但是objectid对于没有保存的prefab不起作用，这里做临时处理，强制保证一下保存。
        {
            EditorGUILayout.LabelField("请先保存修改，再使用本工具");
            return;
        }

        if (Application.isPlaying)
        {
            EditorGUI.BeginChangeCheck();
            playingWatchPrefab = EditorGUILayout.ObjectField("运行界面：", playingWatchPrefab, typeof(GameObject), true) as GameObject;
            if (EditorGUI.EndChangeCheck())
            {
                Refresh();
            }
        }

        for (int i = 0, len = Prefabs.Count; i < len; ++i)
        {
            if (UIEditorDatas.Count <= i)
                continue;

            var prefab = Prefabs[i];
            if (prefab == null)
            {
                Refresh();
                return;
            }

            UIEditorData uiData = UIEditorDatas[i];
            EditorGUILayout.BeginHorizontal();
            _foldouts[i] = EditorGUILayout.Foldout(_foldouts[i], _foldouts[i] ? "收起" : "展开", true);
            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.ObjectField("预制体：", prefab, typeof(GameObject), true);
            EditorGUI.EndDisabledGroup();
            EditorGUILayout.EndHorizontal();
            if (_foldouts[i])
            {
                EditorGUILayout.BeginVertical("Box");
                if (isUseDebugTool || isUseAdminTool)
                {
                    EditorGUILayout.BeginHorizontal();
                    copyData = EditorGUILayout.ObjectField(copyData, typeof(UIEditorData), true) as UIEditorData;
                    if (GUILayout.Button("复制"))
                    {
                        uiData.ResetAll();
                        foreach (var item in copyData.ctrlItemDatas)
                        {
                            var itemData = new CtrlItemData();
                            itemData.Copy(item);
                            uiData.ctrlItemDatas.Add(itemData);
                        }
                        copyData = null;
                    }
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUI.BeginDisabledGroup(true);
                EditorGUILayout.ObjectField("源数据：", uiData, typeof(GameObject), true);
                EditorGUI.EndDisabledGroup();
                if (uiData == null)
                {
                    GUILayout.Label("没有数据");
                }
                else
                {
                    uiData.OnDrawHead(isUseDebugTool || isUseAdminTool);
                }
                EditorGUILayout.EndVertical();
            }


            if (uiData == null)
            {
                GUILayout.Label("没有数据");
            }
            else
            {
                uiData.DrawUIControlData(isUseDebugTool || isUseAdminTool);
            }

            var errors = CheckCtrlItemErrors(uiData.ctrlItemDatas);
            if (errors != null && errors.Count > 0)
            {
                GUI.color = new Color(1.0f, 0.0f, 0.0f, 1f);
                _foldWarning = EditorGUILayout.Foldout(_foldWarning, _foldWarning ? "收起" : "数据有错误", true);
                GUI.color = Color.white;
                if (_foldWarning)
                {
                    for (int j = 0; j < errors.Count; ++j)
                    {
                        EditorGUILayout.LabelField(errors[j]);
                    }
                }
            }

            EditorGUI.BeginDisabledGroup(!CheckErrors(uiData, false));
            if (GUILayout.Button("生成代码"))
            {
                //var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
                //if (prefabStage != null) //手动保存prefab，因为使用objectid来索引对象的前提条件是需要保存下来，不保存的对象是拿不到objectid的。
                //{
                //    PrefabUtility.SaveAsPrefabAsset(prefabStage.prefabContentsRoot, prefabStage.assetPath);
                //    prefabStage.ClearDirtiness();
                //}
                GenerateCode(uiData, true);
            }

            //EditorGUILayout.BeginHorizontal();
            //if (GUILayout.Button("复制按钮注册代码"))
            //{
            //    withClickFunc = true;
            //    CopyViewModelToClipBoard(i, withClickFunc);
            //}
            //EditorGUILayout.LabelField("按钮函数：", GUILayout.MaxWidth(60));
            //withClickFunc = EditorGUILayout.Toggle(withClickFunc, GUILayout.MaxWidth(20));
            //EditorGUILayout.EndHorizontal();
            EditorGUI.EndDisabledGroup();

#if ExtraFunc
                if (GUILayout.Button("SVN提交") && CheckErrors(uiData))
                {
                    DoSVNCommit(uiData, null);
                }
#endif
        }
    }

    private List<string> CheckCtrlItemErrors(List<CtrlItemData> ctrlItemDatas, bool hasWarning = true)
    {
        var result = new List<string>(30);

        #region 名字为空
        for (int i = 0; i < ctrlItemDatas.Count; ++i)
        {
            if (string.IsNullOrEmpty(ctrlItemDatas[i].name))
                result.Add(string.Format("无名：编号{0}", i));
        }
        #endregion 名字为空

        //#region 引用为空
        //for (int i = 0; i < ctrlItemDatas.Count; ++i)
        //{
        //    if (ctrlItemDatas[i].GetTargets() == null)
        //        result.Add(string.Format("无引用：编号{0}", i));
        //}
        //#endregion 引用为空

        #region 重名
        Dictionary<string, int> checkDictionary = new Dictionary<string, int>();
        for (int i = 0; i < ctrlItemDatas.Count; ++i)
        {
            var item = ctrlItemDatas[i];
            if (string.IsNullOrEmpty(item.name))
                continue;
            if (item.isList)
                continue;

            int first = 0;
            if (checkDictionary.TryGetValue(item.name, out first))
            {
                result.Add(string.Format("重名：编号{0}和编号{1}", first, i));
            }
            else
            {
                checkDictionary.Add(item.name, i);
            }
        }
        #endregion 重名

        return result;
    }

    public bool CheckErrors(UIEditorData uiData, bool isWarning = true)
    {
        if (uiData == null)
        {
            if (isWarning)
                EditorUtility.DisplayDialog("错误", "数据错误", "OK");
            return false;
        }

        var errors = CheckCtrlItemErrors(uiData.ctrlItemDatas, false);
        if (errors != null && errors.Count > 0)
        {
            if (isWarning)
                EditorUtility.DisplayDialog("错误", "还有错误没有解决", "OK");
            return false;
        }

        return true;
    }

    public void Refresh()
    {
        Prefabs.Clear();
        UIEditorDatas.Clear();
        _foldouts.Clear();
        var window = FindAllUIPrefab(out var path);
        if (window == null)
            return;

        Prefabs.Add(window);
        _foldouts.Add(false);

        var name = window.name;
        var data = GetUIEditorData(name, true); //TODO UI数据分层 解析路径 key = name
        if (!data.IsVaild())
        {
            if (window.GetComponent<CanvasScaler>() != null)
            {
                data.isChild = 0;
            }
            else
            {
                data.isChild = 3;
            }
            data.isChild = 0; //TODO 目前不区分子界面
        }
        data.DoInit(path, window);
        UIEditorDatas.Add(data);
    }

    public static void GenerateCode(UIEditorData uiData, bool withVM = false)
    {
        CheckWriteAsset(uiData);
        EditorUtility.SetDirty(uiData);
        AssetDatabase.SaveAssetIfDirty(uiData);
        AssetDatabase.Refresh();

        WriteClassFile(uiData);
        if (withVM)
        {
#if USE_LUA_CODE
            var path = GetWorkingScriptPath(uiData);
            if (!string.IsNullOrEmpty(path))
            {
                if (File.Exists(path))
                {
                    RefreshLuaWindow(uiData);
                }
                else
                {
                    GenerateLuaWindow(uiData);
                }
            }
#endif
        }
    }

    private static void WriteClassFile(UIEditorData uiData)
    {
        var template = "";
        var path = "";
#if USE_CSHARP_CODE
        path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UICSClassTemplate.txt");
#endif
#if USE_LUA_CODE
        path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UILuaViewClassTemplate.txt");
        if (uiData.isChild == 1)
            path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UILuaViewClassTemplate.txt");
        else if (uiData.isChild == 2)
            path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UILuaGridChildViewClassTemplate.txt");
        else if (uiData.isChild == 3)
            path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UILuaPrivateChildViewClassTemplate.txt");
        else if (uiData.isChild == 4)
            path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, "UILuaActivityViewClassTemplate.txt");
#endif
        using (FileStream fs = new FileStream(path, FileMode.Open))
        {
            var sr = new StreamReader(fs, utf8noBom);
            template = sr.ReadToEnd();
        }

        var viewPath = GetViewScriptPath(uiData);
        var oldViewCode = "";
        if (File.Exists(viewPath))
        {
            using (FileStream fs = new FileStream(viewPath, FileMode.Open))
            {
                var sr = new StreamReader(fs, utf8noBom);
                oldViewCode = sr.ReadToEnd();
            }
        }
        using (FileStream fs = new FileStream(viewPath, FileMode.Create))
        {
            var sw = new StreamWriter(fs, utf8noBom);
            var newViewCode = FormatFile(template, uiData);
            if (!string.IsNullOrEmpty(oldViewCode) && oldViewCode.Contains("-- codeGenerated start"))
            {
                //if (oldViewCode.Contains("-- funcGenerated start"))
                //{
                //    var oldTop = oldViewCode.Split("-- codeGenerated start")[0];
                //    var newMid = newViewCode.Split("-- codeGenerated start")[1].Split("-- codeGenerated end")[0];
                //    var oldMid2 = oldViewCode.Split("-- codeGenerated end")[1].Split("-- funcGenerated start")[0];
                //    var newMid3 = newViewCode.Split("-- funcGenerated start")[1].Split("-- funcGenerated end")[0];
                //    var oldEnd = oldViewCode.Split("-- funcGenerated end")[1];
                //    newViewCode = oldTop + "-- codeGenerated start" + newMid + "-- codeGenerated end" + oldMid2 + "-- funcGenerated start" + newMid3 + "-- funcGenerated end" + oldEnd;
                //}
                //else if (newViewCode.Contains("-- funcGenerated start"))
                //{
                //    var oldTop = oldViewCode.Split("-- codeGenerated start")[0];
                //    var newMid = newViewCode.Split("-- codeGenerated start")[1].Split("-- codeGenerated end")[0];
                //    var oldMid2 = "";
                //    if (oldViewCode.Split("-- codeGenerated end")[1].Contains("function"))
                //    {
                //        oldMid2 = oldViewCode.Split("-- codeGenerated end")[1].Split("function")[0];
                //    }
                //    else
                //    {
                //        oldMid2 = oldViewCode.Split("-- codeGenerated end")[1].Split("return")[0];
                //    }
                //    var newMid3 = newViewCode.Split("-- funcGenerated start")[1].Split("-- funcGenerated end")[0];
                //    var oldEnd = oldViewCode.Split("-- codeGenerated end")[1];
                //    var a = oldEnd.Split("end", 2);
                //    oldEnd = a[1];
                //    newViewCode = oldTop + "-- codeGenerated start" + newMid + "-- codeGenerated end" + oldMid2 + "-- funcGenerated start" + newMid3 + "-- funcGenerated end" + oldEnd;
                //}
                //else
                //{
                //    var newMid = newViewCode.Split("-- codeGenerated start")[1].Split("-- codeGenerated end")[0];
                //    var oldTop = oldViewCode.Split("-- codeGenerated start")[0];
                //    var oldEnd = oldViewCode.Split("-- codeGenerated end")[1];
                //    newViewCode = oldTop + "-- codeGenerated start" + newMid + "-- codeGenerated end" + oldEnd;
                //}
            }
            sw.Write(newViewCode);
            sw.Flush();
        }
    }
    
#if USE_LUA_CODE
    private static void GenerateLuaWindow(UIEditorData uiData)
    {
        var filename = "UILuaWindowClassTemplate.txt";
        if (uiData.isChild == 1)
            filename = "UILuaChildWindowClassTemplate.txt";
        else if (uiData.isChild == 2)
            filename = "UILuaGridChildWindowClassTemplate.txt";
        else if (uiData.isChild == 3)
            filename = "UILuaChildWindowClassTemplate.txt";
        else if (uiData.isChild == 4)
            filename = "UILuaActivityWindowClassTemplate.txt";
        var path = Path.Combine(EditorPathConfig.UI_TEMPLATE_PATH, filename);
        if (string.IsNullOrEmpty(path) || !File.Exists(path))
            return;

        var template = "";
        using (FileStream fs = new FileStream(path, FileMode.Open))
        {
            var sr = new StreamReader(fs);
            template = sr.ReadToEnd();
        }

        path = GetWorkingScriptPath(uiData);
        if (string.IsNullOrEmpty(path) || File.Exists(path))
            return;

        Directory.CreateDirectory(Path.GetDirectoryName(path));
        using (FileStream fs = new FileStream(path, FileMode.Create))
        {
            var sw = new StreamWriter(fs, utf8noBom);
            sw.Write(FormatFile(template, uiData));
            sw.Flush();
            sw.Close();
        }
    }

    private static void RefreshLuaWindow(UIEditorData uiData)
    {
        var path = GetWorkingScriptPath(uiData);
        if (string.IsNullOrEmpty(path) || !File.Exists(path))
            return;

        var oldViewCode = "";
        using (FileStream fs = new FileStream(path, FileMode.Open))
        {
            var sr = new StreamReader(fs, utf8noBom);
            oldViewCode = sr.ReadToEnd();
        }

        var newMid = CtrlItemDataHelper.GetLuaCopyViewModelInit(uiData);

        using (FileStream fs = new FileStream(path, FileMode.Create))
        {
            var viewModelName = CtrlItemDataHelper.GetViewModelName(uiData);
            var splitBegin = string.Format("-- 控件初始化，自动生成请勿手改 start <{0}>\r\n", viewModelName);
            var splitEnd = string.Format("-- 控件初始化，自动生成请勿手改 end <{0}>\r\n", viewModelName);
            var sw = new StreamWriter(fs, utf8noBom);
            if (!string.IsNullOrEmpty(oldViewCode) && oldViewCode.Contains(splitBegin) && oldViewCode.Contains(splitEnd))
            {
                var oldTop = oldViewCode.Split(splitBegin)[0];
                var oldEnd = oldViewCode.Split(splitEnd)[1];
                oldViewCode = oldTop + newMid + oldEnd;
            }
            sw.Write(oldViewCode);
            sw.Flush();
        }
    }
#endif

    public static void GenerateAsset(UIEditorData uiData)
    {
        CheckWriteAsset(uiData);
        var root = AssetDatabase.LoadAssetAtPath<GameObject>(uiData.prefabPath);
        foreach (var item in uiData.ctrlItemDatas)
        {
            item.RefreshTarget(root);
        }

        EditorUtility.SetDirty(uiData);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    public static UIEditorData GetUIEditorData(string name, bool isCreateNew) //TODO UI数据分层 传入路径
    {
        if (UIAssetRawData == null)
        {
            InitUIAssetRawData();
        }
        if (name.EndsWith("(Clone)"))
        {
            name = name.Remove(name.Length - 7);
        }

        if (UIAssetRawData.ContainsKey(name))
        {
            return UIAssetRawData[name];
        }
        else if (isCreateNew)
        {
            UIEditorData uiData = ScriptableObject.CreateInstance<UIEditorData>();
            uiData.name = name;
            uiData.ctrlItemDatas = new List<CtrlItemData>();
            return uiData;
        }
        return null;
    }

    private static Dictionary<string, UIEditorData> UIAssetRawData;
    private static void InitUIAssetRawData()
    {
        UIAssetRawData = new Dictionary<string, UIEditorData>();
        DirectoryInfo folder = new DirectoryInfo(EditorPathConfig.UI_SCRIPTABLEOBJECT_PATH);
        foreach (var file in folder.GetFiles()) //TODO UI数据分层 优化遍历逻辑
        {
            var name = file.Name;
            if (name.EndsWith(".asset"))
            {
                var path = Path.Combine(EditorPathConfig.UI_SCRIPTABLEOBJECT_PATH, name); //TODO UI数据分层 拼接路径
                if (File.Exists(path))
                {
                    var uiData = AssetDatabase.LoadAssetAtPath(path, typeof(UIEditorData)) as UIEditorData;
                    if (uiData != null)
                    {
                        var rawName = Path.GetFileNameWithoutExtension(name); //TODO UI数据分层 传入路径 key = path no extension
                        uiData.ResetAll();
                        UIAssetRawData.Add(rawName, uiData);
                    }
                }
            }
        }
    }

    private static void AddUIAssetRawData(string name, UIEditorData uiData) //TODO UI数据分层 传入路径
    {
        if (UIAssetRawData.ContainsKey(name))
            return;

        UIAssetRawData.Add(name, uiData);
        var path = GetAssetPath(uiData);
        AssetDatabase.CreateAsset(uiData, path);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    private static void CheckWriteAsset(UIEditorData uiData) //具体写数据之前，把数据规范化一下。如果是新的数据，加入全局表。
    {
        uiData.CheckDataCorrect();
        var name = Path.GetFileNameWithoutExtension(uiData.prefabPath); //TODO UI数据分层 解析路径 key = path no extension
        if (!UIAssetRawData.ContainsKey(name))
            AddUIAssetRawData(name, uiData);
    }

    private static string FormatFile(string template, UIEditorData uiData)
    {
        StringBuilder sb = new StringBuilder();
        int startIndex = 0;
        string pattern = "##([_a-zA-Z0-9]+)##";
        foreach (Match match in Regex.Matches(template, pattern))
        {
            sb.Append(template.Substring(startIndex, match.Index - startIndex));
            var name = match.Groups[1].Value;
            var str = CtrlItemDataHelper.GetReflectCode(name, uiData);
            sb.Append(str);
            startIndex = match.Index + match.Value.Length;
        }

        sb.Append(template.Substring(startIndex));
        return sb.ToString();
    }

    public void CopyViewModelToClipBoard(int index, bool withClickFunc)
    {
        var data = UIEditorDatas[index];
        CheckWriteAsset(data);
        CtrlItemDataHelper.CopyViewModelToClipBoardImpl(data, withClickFunc);
    }
    #endregion 程序

    #region 其他工具
    private void DrawTab3Page()
    {
        DrawFindPrefab();
        GUILayout.Space(10);
        DrawFindEmptyAssetFile();
    }

    #region 查找预制体
    private string scriptName;
    private void DrawFindPrefab()
    {
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("类名：");
        scriptName = EditorGUILayout.TextField(scriptName);
        if (GUILayout.Button("查找对应预制体"))
        {
            var lowFinder = scriptName.ToLower();
            foreach (var kv in UIAssetRawData)
            {
                var lowSymbol = kv.Value.GetScriptSymbol().ToLower();
                var lowWindow = lowSymbol + "window";
                var lowView = lowSymbol + "view";
                var lowChild = lowSymbol + "child";
                if (lowSymbol == lowFinder || lowWindow == lowFinder || lowView == lowFinder || lowChild == lowFinder)
                {
                    var prefabPath = kv.Value.prefabPath;
                    var prefabName = Path.GetFileNameWithoutExtension(prefabPath);

                    EditorGUIUtility.systemCopyBuffer = prefabName;
                    UnityEngine.Debug.Log(" 复制prefab名>> " + prefabName);
                    if (File.Exists(prefabPath))
                    {
                        GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)) as GameObject;
                        if (prefab != null)
                        {
                            FindInPrefab.FilterShowAssets(new int[] { prefab.GetInstanceID() });
                        }
                    }
                    break;
                }
            }
        }
        EditorGUILayout.EndHorizontal();
    }
    #endregion 查找预制体

    #region 查找非法Asset
    private List<UIEditorData> EmptyAssetList = new List<UIEditorData>();
    private List<string> EmptyAssetListTag = new List<string>();
    private void DrawFindEmptyAssetFile()
    {
        EditorGUILayout.BeginVertical("box");
        if (EmptyAssetList == null || EmptyAssetList.Count == 0)
        {
            if (GUILayout.Button("查找空的Asset文件"))
            {
                EmptyAssetList.Clear();
                EmptyAssetListTag.Clear();
                foreach (var kv in UIAssetRawData)
                {
                    var uiData = kv.Value;
                    if (!uiData.IsVaild())
                    {
                        UnityEngine.Debug.Log(" 没有ScriptSymbol>> " + uiData.prefabPath);
                        EmptyAssetList.Add(uiData);
                        EmptyAssetListTag.Add("无定义");
                    }
                    else if (string.IsNullOrEmpty(uiData.prefabPath) || !File.Exists(uiData.prefabPath))
                    {
                        UnityEngine.Debug.Log(" 没有prefab>> " + uiData.prefabPath);
                        EmptyAssetList.Add(uiData);
                        EmptyAssetListTag.Add("无预设");
                    }
                    else if ((uiData.ctrlItemDatas == null || uiData.ctrlItemDatas.Count == 0) && uiData.isChild != 2)
                    {
                        UnityEngine.Debug.Log(" 没有数据>> " + uiData.prefabPath);
                        EmptyAssetList.Add(uiData);
                        EmptyAssetListTag.Add("无数据");
                    }
                }
            }
        }
        else
        {
            GUILayout.Label("总数：" + EmptyAssetList.Count);
            for (int i = 0; i < EmptyAssetList.Count; i++)
            {
                var data = EmptyAssetList[i];
                EditorGUILayout.BeginHorizontal();
                EditorToolsUtils.DrawTextTag(EmptyAssetListTag[i], Color.white, Color.black);
                EditorGUILayout.TextField("文件名：" + data.name + " ScriptSymbol名：" + data.GetScriptSymbol());
                if (GUILayout.Button("删除"))
                {
                    DoDeleteAssetFile(i, data);
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.EndVertical();
                    return;
                }
                EditorGUILayout.EndHorizontal();
            }
        }
        EditorGUILayout.EndVertical();
    }

    private void DoDeleteAssetFile(int i, UIEditorData uiData)
    {
        var scriptSymbol = uiData.GetScriptSymbol();
        
#if ExtraFunc
        //删除View
        var viewPath = GetViewScriptPath(uiData);
        if (File.Exists(viewPath))
        {
            File.Delete(viewPath);
        }
        else
        {
            UnityEngine.Debug.LogError("删除失败：" + viewPath);
        }

        //删除ViewModel
        var viewModelPath = GetWorkingScriptPath(uiData);
        if (File.Exists(viewModelPath))
        {
            File.Delete(viewModelPath);
        }
        else
        {
            UnityEngine.Debug.LogError("删除失败：" + viewModelPath);
        }
#endif

        //删除Asset文件
        var assetPath = GetAssetPath(uiData);
        if (File.Exists(assetPath))
        {
            File.Delete(assetPath);
        }
        else
        {
            UnityEngine.Debug.LogError("删除失败：" + assetPath);
        }
        var assetMetaPath = assetPath + ".meta";
        if (File.Exists(assetMetaPath))
        {
            File.Delete(assetMetaPath);
        }
        else
        {
            UnityEngine.Debug.LogError("删除失败：" + assetMetaPath);
        }

        //删除UIAssetRawData
        EmptyAssetList.RemoveAt(i);
        EmptyAssetListTag.RemoveAt(i);
        UIAssetRawData.Remove(scriptSymbol); //TODO UI数据分层 读取路径 key = scriptSymbol
    }
    #endregion 查找非法Asset

    #endregion 其他工具

    #region Debug工具
    public bool debugFullData = false;
    public bool[] debugFoldouts = new bool[5] { true, true, true, true, true };
    Vector2 debugScrollPos;
    public string curGlobal = "";
    public string curStack = "";
    public string curViewPool = "";
    public string curActionQueue = "";
    public string actionHistory = "";

    private GUIStyle richStyle = new GUIStyle();

    private void DrawTab4Page()
    {
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("详细信息：", GUILayout.MaxWidth(60));
        debugFullData = EditorGUILayout.Toggle(debugFullData, GUILayout.MaxWidth(20));
        EditorGUILayout.EndHorizontal();

        if (GUILayout.Button("刷新数据"))
        {
            OnClick();
        }

        debugFoldouts[0] = EditorGUILayout.Foldout(debugFoldouts[0], "全局界面", true);
        if (debugFoldouts[0])
            GUILayout.Label(curGlobal, richStyle);
        debugFoldouts[1] = EditorGUILayout.Foldout(debugFoldouts[1], "界面堆栈", true);
        if (debugFoldouts[1])
            GUILayout.Label(curStack, richStyle);
        debugFoldouts[2] = EditorGUILayout.Foldout(debugFoldouts[2], "界面池子", true);
        if (debugFoldouts[2])
            GUILayout.Label(curViewPool, richStyle);
        debugFoldouts[3] = EditorGUILayout.Foldout(debugFoldouts[3], "当前命令集", true);
        if (debugFoldouts[3])
            GUILayout.Label(curActionQueue, richStyle);
        debugFoldouts[4] = EditorGUILayout.Foldout(debugFoldouts[4], "历史命令", true);
        if (debugFoldouts[4])
        {
            using (var scrollView = new EditorGUILayout.ScrollViewScope(debugScrollPos))
            {
                debugScrollPos = scrollView.scrollPosition;
                GUILayout.Label(actionHistory, richStyle);
            }
        }
    }

    private void OnClick()
    {
        RefreshDebugShowData();
    }

    private void RefreshDebugShowData()
    {
        curGlobal = "";
        curStack = "";
        curViewPool = "";
        curActionQueue = "";
        actionHistory = "";

#if USE_LUA_CODE
        var luaModule = LuaModule.Instance;
        if (null != luaModule && luaModule.HasInitCompleted)
        {
            curGlobal = luaModule.CallFunctionInvoke<bool, string>("UIManager.getCurGlobal", debugFullData);
            curStack = luaModule.CallFunctionInvoke<bool, string>("UIManager.getCurStack", debugFullData);
            curViewPool = luaModule.CallFunctionInvoke<bool, string>("UIManager.getCurViewPool", debugFullData);
            curActionQueue = luaModule.CallFunctionInvoke<bool, string>("UIManager.getCurActionQueue", debugFullData);
            actionHistory = luaModule.CallFunctionInvoke<bool, string>("UIManager.getActionHistory", debugFullData);
        }
#else
#endif
    }
    #endregion Debug工具

    #region Tools
    //显示RaycastTarget
    [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected)]
    private static void DrawGizmos(MaskableGraphic source, GizmoType gizmoType)
    {
        if (!isRaycastTarget)
            return;

        if (window != null && source.raycastTarget)
        {
            Vector3[] corners = new Vector3[4];
            source.rectTransform.GetWorldCorners(corners);
            Gizmos.color = Color.blue; //todo config
            for (int i = 0; i < 4; i++)
            {
                Gizmos.DrawLine(corners[i], corners[(i + 1) % 4]);
            }
            if (Selection.activeGameObject == source.gameObject)
            {
                Gizmos.DrawLine(corners[0], corners[2]);
                Gizmos.DrawLine(corners[1], corners[3]);
            }
        }
        SceneView.RepaintAll();
    }

    public static GameObject playingWatchPrefab;
    private GameObject FindAllUIPrefab(out string path)
    {
        path = "";
        if (Application.isPlaying)
        {
            if (playingWatchPrefab == null)
                return null;
            var name = playingWatchPrefab.name; //TODO UI数据分层 解析路径 key = name
            if (name.Contains("_"))
                name = name.Split('_')[0];
            var data = GetUIEditorData(name, false); //TODO UI数据分层 解析路径 key = name
            if (data == null)
                return null;

            path = data.prefabPath;
            return playingWatchPrefab;
        }

        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); //todo 归一root获取途径
        if (prefabStage != null)
        {
            path = prefabStage.assetPath;
            return prefabStage.prefabContentsRoot;
        }

        return null;
    }

    private void RefreshAllUIPrefabSafeArea()
    {
        var rectTransforms = new List<RectTransform>();
        var window = FindAllUIPrefab(out var path);
        //UIFactory.RefreshUIPrefabSafeArea(window, mIsLiuHai);
    }

    private void InitPrefabFormat()
    {
        //// 打开Prefab编辑界面回调
        PrefabStage.prefabStageOpened += OnPrefabStageOpened;
        //// Prefab被保存之前回调
        //PrefabStage.prefabSaving += OnPrefabSaving;
        //// Prefab被保存之后回调
        //PrefabStage.prefabSaved += OnPrefabSaved;
        // 关闭Prefab编辑界面回调
        PrefabStage.prefabStageClosing += OnPrefabStageClosing;
    }

    private void ClearPrefabFormat()
    {
        //// 打开Prefab编辑界面回调
        PrefabStage.prefabStageOpened -= OnPrefabStageOpened;
        //// Prefab被保存之前回调
        //PrefabStage.prefabSaving -= OnPrefabSaving;
        //// Prefab被保存之后回调
        //PrefabStage.prefabSaved -= OnPrefabSaved;
        //// 关闭Prefab编辑界面回调
        PrefabStage.prefabStageClosing -= OnPrefabStageClosing;
    }

    private void OnPrefabStageOpened(PrefabStage obj)
    {
        Refresh();
    }

    private void OnPrefabStageClosing(PrefabStage obj)
    {
        //规范化UI
        FindInPrefab.DoFindInPrefab(3, obj.prefabContentsRoot);

        ////重置toggle状态
        //var toggles = FindObjectsOfType<Toggle>();
        //if (toggles.Length > 0)
        //{
        //    for (int i = 0, len = toggles.Length; i < len; ++i)
        //    {
        //        var toggle = toggles[i];
        //        toggle.onValueChanged.Invoke(toggle.isOn);
        //    }
        //}

        string path = obj.assetPath;
        GameObject root = obj.prefabContentsRoot;
        PrefabUtility.SaveAsPrefabAsset(root, path);
        Refresh();
    }
    
    private void InitHightLightUIControlData()
    {
        EditorApplication.hierarchyWindowItemOnGUI += HierarchyItemCB;
    }

    private void ClearHightLightUIControlData()
    {
        EditorApplication.hierarchyWindowItemOnGUI -= HierarchyItemCB;
    }

    //根据每个东西在不在asset里判断是否需要高亮
    private static void HierarchyItemCB(int instanceid, Rect selectionrect)
    {
        if (EditorApplication.isPlaying)//运行时不触发
            return;

        var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();//不是prefab编辑模式不触发 //todo 归一root获取途径
        if (prefabStage == null)
            return;

        var data = GetUIEditorData(prefabStage.prefabContentsRoot.name, false); //TODO UI数据分层 解析路径 key = name
        var obj = EditorUtility.InstanceIDToObject(instanceid);
        var go = obj as GameObject;
        if (go != null && data != null && data.ctrlItemDatas != null)
        {
            for (int i = 0; i < data.ctrlItemDatas.Count; i++)
            {
                var ctrlItem = data.ctrlItemDatas[i];
                if (go == ctrlItem.GetTargets(prefabStage.prefabContentsRoot, onlyGO: true))
                {
                    Rect r = new Rect(selectionrect);
                    r.x = 0;
                    r.width = 100;
                    var style = new GUIStyle();
                    style.normal.textColor = Color.green;
                    GUI.Box(r, i.ToString(), style);
                    break;
                }
            }
        }

        var hmi = go?.GetComponent<HMI_ComponentBase>();
        if (hmi != null)
        {
            Rect r = new Rect(selectionrect);
            r.x = r.x - 15;
            r.width = 15;
            Color color;
            //if (GUIUtility.hotControl == (instanceid + 10000000))
            //{
            //    color = new Color(0.17f, 0.365f, 0.53f);
            //}
            //else if (GUIUtility.hotControl > 0 && GUIUtility.hotControl != (instanceid + 10000000)
            //    && !((Event.current.type == EventType.KeyDown) && 
            //    (Event.current.keyCode == KeyCode.LeftShift || Event.current.keyCode == KeyCode.RightShift
            //    || Event.current.keyCode == KeyCode.LeftControl || Event.current.keyCode == KeyCode.RightControl)))
            //{
            //    color = new Color(0.22f, 0.22f, 0.22f);
            //}
            //else if (Selection.instanceIDs.Any((x) => x == instanceid))
            //{
            //    color = new Color(0.17f, 0.365f, 0.53f);
            //}
            //else
            {
                color = new Color(0.22f, 0.22f, 0.22f);
            }
            EditorGUI.DrawRect(r, color);
        }
    }

    #if ExtraFunc
    private static void DoSVNCommit(UIEditorData uiData, string prefabPath)
    {
        List<string> paths = new List<string>(7);
        var p = uiData.prefabPath; //prefab
        if (File.Exists(p))
            paths.Add(p);
        p = p + ".meta"; //prefab.meta
        if (File.Exists(p))
            paths.Add(p);

        if (uiData.IsVaild())
        {
            p = GetAssetPath(uiData); //asset
            if (!string.IsNullOrEmpty(p))
            {
                if (File.Exists(p))
                    paths.Add(p);
                p = p + ".meta"; //asset.meta
                if (File.Exists(p))
                    paths.Add(p);
            }
            p = GetWorkingScriptPath(uiData); //vm.lua
            if (File.Exists(p))
                paths.Add(p);
            p = GetViewScriptPath(uiData); //view.lua
            if (File.Exists(p))
                paths.Add(p);
        }

        if (!string.IsNullOrEmpty(prefabPath))
        {
            var depends = AssetDatabase.GetDependencies(prefabPath);
            for (int i = 0; i < depends.Length; i++)
            {
                if (depends[i].StartsWith("Packages"))
                    continue;

                if (depends[i].EndsWith(".cs"))
                    continue;

                if (depends[i].Contains("UI/Font/"))
                    continue;

                paths.Add(depends[i]);
                paths.Add(depends[i] + ".meta");
            }
        }
        //Framework.Editor.Tools.SVNMultiCommit.Commit(paths);
    }
    #endif

    #region Path


    private static string GetAssetPath(UIEditorData uiData)
    {
        if (!uiData.IsVaild())
            return "";

        return Path.Combine(EditorPathConfig.UI_SCRIPTABLEOBJECT_PATH, uiData.name + ".asset"); //TODO UI数据分层 拼接路径
    }

#if ExtraFunc
    private static string GetWorkingScriptPath(UIEditorData uiData)
    {
        if (uiData == null)
            return "";

        var path = EditorPathConfig.UI_WORKING_SCRIPT_PATH;
        if (!string.IsNullOrEmpty(uiData.ScriptFolder))
        {
            path = Path.Combine(path, uiData.ScriptFolder);
        }

        var scriptSymbol = uiData.GetScriptSymbol();

        if (uiData.isChild != 0)
        {
#if USE_CSHARP_CODE
            path = Path.Combine(path, scriptSymbol + "Child.cs");
#endif
#if USE_LUA_CODE
            path = Path.Combine(path, scriptSymbol + "Child.lua");
#endif
        }
        else
        {
#if USE_CSHARP_CODE
            path = Path.Combine(path, scriptSymbol + "Window.cs");
#endif
#if USE_LUA_CODE
            path = Path.Combine(path, scriptSymbol + "Window.lua");
#endif
        }
        return path;
    }
#endif

    public static string GetViewScriptPath(UIEditorData uiData)
    {
        if (uiData == null)
            return "";

        var filename = "";
#if USE_CSHARP_CODE
        filename = uiData.GetScriptSymbol() + "View.cs";
#endif
#if USE_LUA_CODE
        filename = uiData.GetScriptSymbol() + "View.lua";
#endif
        var path = Path.Combine(EditorPathConfig.UI_SCRIPT_PATH, filename);
        return path;
    }
    #endregion Path
    #endregion Tools

    #region RightClick
    private GenericMenu RightMenu;
    private GenericMenu EditorMenu;
    private void InitRightMenu()
    {
        //RightMenu = new GenericMenu(); //demo
        //RightMenu.AddItem(new GUIContent("打开编辑器代码"), false, OpenEditorWindowCode);
        //RightMenu.AddSeparator("");

        RightMenu = new GenericMenu();
        RightMenu.AddItem(new GUIContent("打开代码"), false, OpenWorkingWindowCode);
        RightMenu.AddItem(new GUIContent("打开View代码"), false, OpenWorkingViewCode);

        if (isAdministrator)
        {
            EditorMenu = new GenericMenu();
            EditorMenu.AddItem(new GUIContent("编辑"), false, ChangeEditorMode);
        }
    }
    private void ClearRightMenu()
    {

    }

    private void DrawRightClick()
    {
        if (window == null)
        {
            window = EditorWindow.GetWindow<UISceneToolWindow>(false, "UI场景工具");
        }
        if (Event.current.type == UnityEngine.EventType.ContextClick && UIEditorDatas.Count > 0)
        {
            RightMenu?.ShowAsContext();
            Event.current.Use();
        }
    }

    private void OpenEditorWindowCode()
    {
        var asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>("Assets/ThirdParty/isletTools/UISceneToolWindow/Editor/UISceneToolWindow.cs");
        AssetDatabase.OpenAsset(asset, 0);
    }

    private void OpenWorkingWindowCode()
    {
#if ExtraFunc
        var uiControlData = UIEditorDatas[0]; //todo 没有适配多个data的情况！！！
        var path = GetWorkingScriptPath(uiControlData);
        OpenWorkingCode(path);
#endif
    }

    private void OpenWorkingViewCode()
    {
        var uiControlData = UIEditorDatas[0]; //todo 没有适配多个data的情况！！！
        var path = GetViewScriptPath(uiControlData);
        OpenWorkingCode(path);
    }

    private void OpenWorkingCode(string path)
    {
        if (Application.platform == RuntimePlatform.WindowsEditor && !string.IsNullOrEmpty(path))
        {
            var psi = new ProcessStartInfo();
            psi.FileName = Path.Combine(Application.dataPath, @"..\Tools\startFile.bat");
            psi.Arguments = path;
            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.CreateNoWindow = true;

            Process process = new Process();
            process.StartInfo = psi;
            process.Start();
        }
    }

    private void ChangeEditorMode()
    {
        isPrefabSetting = !isPrefabSetting;
        if (!isPrefabSetting)
        {
            WriteTemplatePrefab();
        }
    }

    private void ShowButton(Rect position)
    {
        EditorToolsUtils.DrawShowButton(position, @"https://ae-wiki.leapmotor.com/zh/%E5%B5%8C%E5%85%A5%E5%BC%8FHMI%E7%BB%84/Unity%E7%BB%84%E4%BB%B6%E5%92%8C%E5%B7%A5%E5%85%B7%E6%96%87%E6%A1%A3/%E4%BD%BF%E7%94%A8UI%E6%8E%A7%E4%BB%B6%E5%BA%93%E5%B7%A5%E5%85%B7%E5%88%B6%E4%BD%9C%E7%95%8C%E9%9D%A2%E6%B5%81%E7%A8%8B");
    }
    #endregion RightClick

    #region TestFunc
    public void OnTestClick()
    {
        //GameViewUtils.TrySetSize("5:4");
    }
    #endregion TestFunc
}
#endif